Add buf beta registry cargo credential provider#4541
Conversation
Add a new `buf beta registry cargo` subcommand that implements Cargo's
`cargo:token-from-stdout` credential-provider protocol, so Cargo can
obtain a Bearer token for BSR-hosted Cargo registries by shelling out
to buf instead of storing tokens in `credentials.toml`.
Users configure it via `~/.cargo/config.toml`:
[registry]
global-credential-providers = ["cargo:token-from-stdout buf beta registry cargo"]
Behavior:
- Reads CARGO_REGISTRY_INDEX_URL, extracts the host (strips an optional
"sparse+" prefix, lowercases, drops the port).
- Checks the host against a positional-argument allow-list. With no
positional args the allow-list defaults to [buf.build]; positional
args replace (not extend) the default. Ports in positional args are
stripped so they compare equal to URL-extracted hosts.
- For an allow-listed host, resolves a token via the existing bufconnect
chain: BUF_TOKEN env var first, then ~/.netrc.
- On success, writes `Bearer <token>\n` to stdout and exits 0.
- For hosts outside the allow-list (or a missing/unparseable URL),
exits non-zero with no output so Cargo can fall through to its next
configured credential provider.
- For allow-listed hosts with no token, writes a "Failure: ..." message
pointing at `buf registry login` and exits non-zero.
- A malformed BUF_TOKEN produces a redacted user-visible error; the
underlying bufconnect parser error (which embeds the raw token value)
is logged at --debug level only.
No new bufconnect or authentication primitives are introduced; the
command is a thin orchestrator over existing token providers. Cargo
invokes credential providers on every dependency resolution, so the
implementation makes no network calls and constructs no Connect clients.
Includes command-level tests covering the silent/loud contract,
allow-list semantics, BUF_TOKEN precedence over .netrc, host
case-insensitivity, host:port normalization, and a leak-prevention
assertion that the BUF_TOKEN value never reaches stderr.
|
|
|
Thanks for submitting this PR, I've reviewed it and unfortunately, I don't think we'll be merging this feature right now. So my stance on this PR is the UX of the proposed command here is narrow/assumes that the use has run I was wondering if you have explored using a credential provider that pulls from For now, I am closing this PR, but please feel free to follow-up with any questions and if there is anything else I can help with to get to a solution for you. Thanks again! |
|
@doriable I think the key part is that it IS Would you consider something that dropped the |
Summary
Adds a new
buf beta registry cargosubcommand that implements Cargo'scargo:token-from-stdoutcredential-provider protocol. With this in place, Cargo can resolve a Bearer token for a BSR-hosted Cargo registry by shelling out tobuf, instead of users having to copy a token into~/.cargo/credentials.tomland keep two copies in sync.The command is registered under
betaso we have room to iterate on the UX before promoting it.Motivation
Today, a developer pulling crates from a BSR-hosted Cargo registry has to:
buf registry login buf.buildto authenticatebuf.~/.cargo/credentials.toml(orcargo login) so Cargo can use it.Two stores for one secret, two places to rotate, two places to leak. This change lets users delegate the second step to
buf:Now any
cargooperation against a BSR-hosted registry invokesbuf beta registry cargo, which resolves the token from the same chainbufalready uses (BUF_TOKENenv var, then~/.netrc).Configuration
Default — public BSR at
buf.build:Enterprise BSR (positional args replace the default;
buf.buildis not implicitly included):Multiple hosts:
Token management continues to flow through
buf registry login <host>; no Cargo-specific login is required.How it works
On each invocation Cargo sets
CARGO_REGISTRY_INDEX_URL(and other env vars per the spec) and reads a single line from stdout. The command:CARGO_REGISTRY_INDEX_URL(strips an optionalsparse+prefix, parses as a URL, lowercases, drops any port).[buf.build]). Allow-list entries are also lowercased and port-stripped sobsr.example.com:8443matchessparse+https://bsr.example.com:8443/....bufconnect.NewTokenProviderFromContainer(theBUF_TOKENenv var) and falls through tobufconnect.NewNetrcTokenProvider(~/.netrc).Bearer <token>\nto stdout and exits0.No Connect clients are constructed and no network calls are made — credential providers are on the hot path of every dependency resolution.
Failure semantics
CARGO_REGISTRY_INDEX_URLunset, unparseable, or host not in the allow-listFailure: no token found for <host>. Run "buf registry login <host>" ...bufhas no credentials for it — surface a fixBUF_TOKENis malformedFailure: the BUF_TOKEN environment variable could not be parsed. Either unset BUF_TOKEN, or run "buf registry login <host>" .... Underlying parser error is debug-onlybufconnectparse error embeds the raw token value, so the user-visible message is deliberately redactedPass
--debugto log host extraction, allow-list matching, and (when present) the rawBUF_TOKENparser error.Out of scope
cargo login/cargo logoutsupport — thecargo:token-from-stdoutprotocol explicitly doesn't support them.bufconnector any existing authentication primitive; this is a thin orchestrator over what's already there.Test plan
go test -race ./cmd/buf/internal/command/beta/registry/registrycargo/...(15 unit + command-level tests covering the contract matrix: unset URL, default and explicit allow-lists, scoped vs unscopedBUF_TOKEN, scoped-miss → netrc fallthrough, env-wins-over-netrc, netrc match + miss, uppercase URL host, uppercase positional, positionalhost:port, malformedBUF_TOKENwith leak-preventionNotContainsassertion).golangci-lint run ./cmd/buf/internal/command/beta/registry/registrycargo/...— 0 issues.go build ./...andgo vet ./...clean.CARGO_REGISTRY_INDEX_URL.Bearer <token>and exits 0.--debugsurfaces structured logs and (only with--debug) the rawBUF_TOKENparser error.BUF_TOKEN=secret@host,secret@host→ user-facing stderr does not containsecret; only the debug log does.Notes for review
cmd/buf/internal/command/beta/registry/registrycargo. The only touches outside it are a 2-line wiring change incmd/buf/buf.goand a 1-lineCHANGELOG.mdentry.errSilentsentinel for silent exits, following the same pattern asprivate/pkg/bandeps/cmd/bandeps/main.go. The top-levelwrapErrorincmd/buf/buf.goalready bypasses itsFailure:prefix whenerr.Error() == "".betaper the design discussion; promote tobuf registry cargoonce we've shipped to early users.